#include "renderwidget.h"
#include "ResourceManger/resourceswidget.h"
#include "ui_renderwidget.h"
#include "eventcenter.h"
#include "math.h"
#include<QtMath>
#include<QDebug>
#include <QHBoxLayout>
#include <QRandomGenerator>
GLfloat vertices[] = {
    -1.0f, -1.0f, 0.001f,
    1.0f, -1.0f, 0.001f,
    1.0f,  1.0f, 0.001f,
    1.0f,  1.0f, 0.001f,
    -1.0f,  1.0f, 0.001f,
    -1.0f, -1.0f, 0.001f
};
GLfloat verticesTexturePostion[] = {
    1.0f,0.0f,
    0.0f,0.0f,
    0.0f,1.0f,
    0.0f,1.0f,
    1.0f,1.0f,
    1.0f,0.0f,
};
RenderWidget::RenderWidget(QWidget *parent) :
    QOpenGLWidget(parent),
    ui(new Ui::RenderWidget)
{
    Init();
}

RenderWidget::~RenderWidget()
{
    delete ui;
    delete myShader;
    delete camera;
    delete outLineTexture;
    delete core;
    delete chosen;
    delete gameMainWindow;
    delete option;
    delete timer;
}

Option* RenderWidget::GetOptionWidget()
{
    return option;
}

void RenderWidget::SetParticleDisabled(bool disable)
{
    activeParticle = !disable;
    //该函数被调用说明粒子系统被更新
    for(int i = 0; i < particles.count();i++)
    {
        Particle* p = particles[i];
        particles[i] = nullptr;
        if(ps)
        {
            ps->ReturnParticle(p);
        }
    }
    particles.clear();
}

void RenderWidget::initializeGL()
{
    core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
    core->glEnable(GL_DEPTH_TEST);
    //透明
    core->glEnable(GL_ALPHA_TEST);
    core->glEnable(GL_BLEND); //开混合模式贴图
    core->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);// 指定混合模式算法
    myShader = new Shader(QString(":/shader/texture.vert"),QString(":shader/texture.frag"));
    InitVAOandVBO();
    core->glActiveTexture(GL_TEXTURE0);

    myShader->shaderProgram.setUniformValue(myShader->shaderProgram.uniformLocation("ourTexture"),0);
    camera = new Camera(QVector3D(0.0f, 0.0f, 0.0f), this->width(), this->height());
    myShader->use();

    emit EventCenter::Instance().RenderInitOver();
}
void RenderWidget::paintGL()
{
    core->glClearColor(0.3,0.3,0.3,1);
    core->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    camera->DealKeyboardInputs();
    //core->glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//画线，第二个参数改成GL_FILL为画面
    //相机的位置会改变，因此在绘图循环中设置mvp
    QMatrix4x4 projection;
    projection.perspective(camera->fov, this->width() / this->height(), 0.1f, 100.f);
    core->glActiveTexture(GL_TEXTURE0);
    myShader->setMat4("view", camera->getViewMat());
    myShader->setMat4("projection", projection);
    float time = QTime::currentTime().msec();
    myShader->setFloat("msec",time);
    //layer小的要在layer大的调用后再调用，否则透明检测失效（应该是画家算法

    for (QMap<int,RenderTarget*>::const_iterator it = renderList.constEnd() - 1; it != renderList.constBegin() - 1; it--)
    {
        Draw(it.value());
    }
    if(chosen && !EventCenter::Instance().GetApplicationMode())
        DrawChosenOutline();
    if(activeParticle)
        DrawParticle();
    if(!timer)
    {
        timer = new QTimer();
        timer->start((float) 1000.0f / 60.0f);
        connect(timer,&QTimer::timeout,this,[=](){update();});
        update();
    }
}

void RenderWidget::resizeGL(int w, int h)
{
    if(gameMainWindow)
    {
        gameMainWindow->setFixedSize(w,h);

    }
    if(option)
    {
        float x = (w - option->size().width()) / 2.0f;
        float y = (h - option->size().height()) / 2.0f;
        option->move(x,y);
    }
    GameUIContainer::Instance().resize(w,h);
    update();
}

void RenderWidget::keyPressEvent(QKeyEvent *event)
{
    update();
    int key = event->key();
    if (key >= 0 && key < 1024)
        camera->keys[key] = GL_TRUE;
}

void RenderWidget::keyReleaseEvent(QKeyEvent * event)
{
    int key = event->key();
    if (key >= 0 && key < 1024)
        camera->keys[key] = GL_FALSE;
}

void RenderWidget::mouseMoveEvent(QMouseEvent * event)
{
    GLint xpos = event->pos().x();
    GLint ypos = event->pos().y();
    if (camera->isLeftMousePress)
    {
        if(camera->moveCamera)
        {
            if (camera->isFirstMouse)
            {
                camera->lastX = xpos;
                camera->lastY = ypos;
                camera->isFirstMouse = GL_FALSE;
            }
            GLint Xoffset = xpos - camera->lastX;
            GLint Yoffset = camera->lastY - ypos;
            camera->lastX = xpos;
            camera->lastY = ypos;
            camera->DealMouseMovement(Xoffset, Yoffset);
        }
        else if(chosen && this->cursor() == Qt::SizeAllCursor)
        {
            QVector2D pos = GetMouseNDC() - MoveImageOffset;
            chosen->SetPos(pos);
            emit this->RefreshChosen();
        }
    }
}

void RenderWidget::mousePressEvent(QMouseEvent * event)
{
    if (event->button() == Qt::LeftButton)
    {
        camera->isLeftMousePress = GL_TRUE;
        if(EventCenter::Instance().GetApplicationMode())
            emit EventCenter::Instance().NextDialog();
    }
    if (event->button() == Qt::RightButton)
    {
        camera->isMouseRightPress = !camera->isMouseRightPress;
        camera->DealMouseRightPress();
    }

    if(EventCenter::Instance().GetApplicationMode())//release
        return;
    switch(state)
    {
    case RenderWidget::MOVE_IMAGE:
        MoveImageMousePress(event);
        break;
    case RenderWidget::SELECT:
        SelectMousePress(event);
        break;
    default:
        break;
    }
}

void RenderWidget::MoveImageMousePress(QMouseEvent *event)
{
    if(!chosen) return;
    this->setCursor(Qt::SizeAllCursor);
    QVector2D mousePos = GetMouseNDC();
    MoveImageOffset = mousePos - chosen->GetPos();
}

void RenderWidget::SelectMousePress(QMouseEvent *event)
{
    QVector2D pos = GetMouseNDC();
    float x = pos.x();
    float y = pos.y();
    for (QMap<int,RenderTarget*>::const_iterator it = renderList.constBegin(); it != renderList.constEnd(); it++)
    {
        float minX = (float)it.value()->GetPos().x() - (float)it.value()->size->x() - camera->cameraPos.x();
        float maxX = (float)it.value()->GetPos().x() + (float)it.value()->size->x() - camera->cameraPos.x();
        float minY = (float)it.value()->GetPos().y() - (float)it.value()->size->y() - camera->cameraPos.y();
        float maxY = (float)it.value()->GetPos().y() + (float)it.value()->size->y() - camera->cameraPos.y();

        if(x > minX && x < maxX && y > minY && y < maxY)
        {
            if(chosen == it.value())
            {
                chosen = nullptr;
            }
            else
            {
                chosen = it.value();
            }
            emit ChosenChange(chosen);
            break;
        }
    }
}

void RenderWidget::mouseReleaseEvent(QMouseEvent * event)
{
    if (event->button() == Qt::LeftButton) {
        camera->isLeftMousePress = GL_FALSE;
        camera->isFirstMouse = GL_TRUE;
    }
    switch(state)
    {
    case RenderWidget::MOVE_IMAGE:
        break;
    case RenderWidget::SELECT:
        break;
    default:
        break;
    }
}

void RenderWidget::dragEnterEvent(QDragEnterEvent *event)
{
    event->acceptProposedAction();
}

void RenderWidget::dropEvent(QDropEvent *event)
{
    ResourceListWidget *i = dynamic_cast<ResourceListWidget*>(event->source());
    if(i)
    {
        QString path = i->GetCurItemPath();
        QDir d;
        path = d.relativeFilePath(path);
        if(FileManager::GetFileType(path) == FileManager::IMAGE)
        {
            emit EventCenter::Instance().DragImage(path);
            emit EventCenter::Instance().Modify();
        }
    }
    else
        qDebug()<<"拖入失败";
}

void RenderWidget::Init()
{
    InitUI();
    CursorChange(state);
    this->setAcceptDrops(true);
    connect(&EventCenter::Instance(),&EventCenter::ChangeParticleSystem,[=](ParticleSystemInfo* info){
        if(!info)
        {
            activeParticle = false;
            return;
        }
        if(!ps)
            ps = new ParticleSystem();
        ps->info = info;
        activeParticle = true;
    });
    GameUIContainer::Instance().setParent(this);
    GameUIContainer::Instance().hide();
}

void RenderWidget::SetDialog(QString text, QString name)
{
    gameMainWindow->SetName(name);
    gameMainWindow->SetDialogText(text);
}

void RenderWidget::ClearRenderList()
{
    renderList.clear();
    chosen = nullptr;
    emit ChosenChange(nullptr);
}

void RenderWidget::AddRenderTarget(RenderTarget *rt, bool adjust_layer, bool force_override)
{
    rt->Activate();
    if(!force_override && renderList.contains(rt->GetLayer()))
    {
        qDebug()<<rt->GetPath()<<"添加失败，层级已包含其他图片";
        return;
    }
    int layer = rt->GetLayer();
    if(renderList.contains(layer))
    {
        if(!adjust_layer)
        {
            qDebug()<<"Layer"<<layer<<"的"<<rt->GetPath()<<"添加失败，层级已包含其他图片";
            return;
        }
        while(renderList.contains(layer) && adjust_layer)
        {
            layer--;
        }
    }
    renderList.insert(layer,rt);
}

void RenderWidget::InitVAOandVBO()
{
    core->glGenVertexArrays(1, &VAO);
    core->glBindVertexArray(VAO);
    core->glGenBuffers(1,&VBO);
    core->glGenBuffers(1,&VBOTexturePos);
    core->glBindBuffer(GL_ARRAY_BUFFER, VBO);
    core->glBufferData(GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW);
    core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof (GLfloat), (void*)0);
    core->glEnableVertexAttribArray(0);
    core->glBindBuffer(GL_ARRAY_BUFFER, VBOTexturePos);
    core->glBufferData(GL_ARRAY_BUFFER, sizeof(verticesTexturePostion), verticesTexturePostion, GL_STATIC_DRAW);
    core->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
    core->glEnableVertexAttribArray(1);
    core->glBindVertexArray(0);
    core->glBindBuffer(GL_ARRAY_BUFFER,0);
    core->glBindVertexArray(VAO);
}

void RenderWidget::Draw(RenderTarget *rt)
{
    QMatrix4x4 model;
    float sizeTimes = rt->sizeTimes;
    QVector2D pos = rt->GetPos();
    model.translate(pos.x(),pos.y(),0);
    float w = rt->GetWidth(), h = rt->GetHeight();
    float winW = this->width(),winH = this->height();

    float x = sizeTimes*(winH/winW)*(w/h);
    float y = sizeTimes*(winW/winH)*(h/w);
    if(w < h)
    {
        if(!rt->size)
        {
            rt->size = new QVector2D(x,sizeTimes);
        }
        model.scale(x,sizeTimes,rt->GetLayer());
        rt->size->setX(x);
        rt->size->setY(sizeTimes);
    }
    else
    {
        if(!rt->size)
        {
            rt->size = new QVector2D(sizeTimes,y);
        }
        model.scale(sizeTimes,y,rt->GetLayer());
        rt->size->setX(sizeTimes);
        rt->size->setY(y);
    }
    myShader->setMat4("model",model);

    rt->GetTexture()->bind();
    core->glDrawArrays(GL_TRIANGLES, 0, 6);
}

void RenderWidget::DrawChosenOutline()
{
    QMatrix4x4 model;
    float sizeTimes = chosen->sizeTimes;
    QVector2D pos = chosen->GetPos();
    model.translate(pos.x(),pos.y(),0);
    float w = chosen->GetWidth(), h = chosen->GetHeight();
    float winW = this->width(),winH = this->height();
    if(w < h)
    {
        model.scale(sizeTimes*(winH/winW)*(w/h),sizeTimes,0);
    }
    else
    {
        model.scale(sizeTimes,sizeTimes*(winW/winH)*(h/w),0);
    }
    myShader->setMat4("model",model);
    myShader->setBool("outline",true);
    core->glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    core->glDrawArrays(GL_TRIANGLES, 0, 6);
    myShader->setBool("outline",false);
    core->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

void RenderWidget::MoveImageState()
{
    this->setCursor(Qt::SizeAllCursor);
    state = MOVE_IMAGE;
}

void RenderWidget::SelectState()
{
    this->setCursor(Qt::ArrowCursor);
    state = SELECT;
}

QVector2D RenderWidget::GetMouseNDC()
{
    QPoint screenPos = mapFromGlobal(QCursor::pos());
    float x = 1.0f - (2.0f * (float)screenPos.x() / (float)this->width());
    float y = 1.0f - (2.0f * (float)screenPos.y() / (float)this->height());
    return QVector2D(x,y);
}

void RenderWidget::InitUI()
{
    gameMainWindow = new GameMainWindow();
    gameMainWindow->setParent(this);
    option = new Option();
    option->setParent(this);
    float x = (this->width() - option->size().width()) / 2.0f;
    float y = (this->height() - option->size().height()) / 2.0f;
    option->move(x,y);
}

void RenderWidget::DrawParticle()
{
    if(!activeParticle)
    {
        return;
    }
    if(!ps)
    {
        ps = new ParticleSystem();
    }
    if(!ps->info)
    {
        emit EventCenter::Instance().GetParticleInfo();
    }
    if(!ps->info)
        return;
    int need = ps->info->maxCount - particles.count();
    for(int i = 0;i < need;i++)
    {
        Particle* p = ps->GetParticle();
        if(p)
            particles.push_back(p);
    }
    float z = -0.01f;
    int i = 0;
    while(i < particles.count())
    {   Particle* p = particles[i];
        if(!p)
        {
            i++;
            continue;
        }
        //回收
        float scope = 1.2;
        if(p->x0 >= scope || p->x0 <= -scope || p->y0 >= scope || p->y0 <= -scope)
        {
            particles.remove(i);
            ps->ReturnParticle(p);
            continue;
        }

        QOpenGLTexture* tex = ps->info->GetTexture(p->texIndex);
        if(!tex)
            continue;
        QMatrix4x4 model;
        model.translate(p->x0,p->y0,z);
        model.scale(p->xsize,p->ysize,z * i);
        myShader->setMat4("model",model);
        tex->bind();
        core->glDrawArrays(GL_TRIANGLES,0,6);

        //更新位置，暂时不写z
        p->x0 += p->xv;
        p->y0 += p->yv;
        p->xv += p->xa;
        p->yv += p->ya;

        i++;
    }
}

void RenderWidget::CursorChange(RenderWidget::CursorState state)
{
    switch (state)
    {
    case RenderWidget::MOVE_IMAGE:
        MoveImageState();
        break;
    case RenderWidget::SELECT:
        SelectState();
        break;
    default:
        break;
    }
}

